/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2014 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package io.undertow.servlet.handlers;

import io.undertow.server.HttpServerExchange;
import io.undertow.servlet.spec.HttpServletRequestImpl;

import javax.servlet.ServletOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;

/**
 * generates a servlet error page with a stack trace
 *
 * @author Stuart Douglas
 */
public class ServletDebugPageHandler {


    public static final String ERROR_CSS =
            "<style>\n" +
            "body {\n" +
                    "    font-family: \"Lucida Grande\", \"Lucida Sans Unicode\", \"Trebuchet MS\", Helvetica, Arial, Verdana, sans-serif;\n" +
                    "    margin: 5px;\n" +
                    "}\n" +
                    "\n" +
                    ".header {\n" +
                    "    background-image: linear-gradient(bottom, rgb(153,151,153) 8%, rgb(199,199,199) 54%);\n" +
                    "    background-image: -o-linear-gradient(bottom, rgb(153,151,153) 8%, rgb(199,199,199) 54%);\n" +
                    "    background-image: -moz-linear-gradient(bottom, rgb(153,151,153) 8%, rgb(199,199,199) 54%);\n" +
                    "    background-image: -webkit-linear-gradient(bottom, rgb(153,151,153) 8%, rgb(199,199,199) 54%);\n" +
                    "    background-image: -ms-linear-gradient(bottom, rgb(153,151,153) 8%, rgb(199,199,199) 54%);\n" +
                    "    \n" +
                    "    background-image: -webkit-gradient(\n" +
                    "        linear,\n" +
                    "        left bottom,\n" +
                    "        left top,\n" +
                    "        color-stop(0.08, rgb(153,151,153)),\n" +
                    "        color-stop(0.54, rgb(199,199,199))\n" +
                    "    );\n" +
                    "    color: black;\n" +
                    "    padding: 2px;\n" +
                    "    font-weight: normal;\n" +
                    "    border: solid 1px;\n" +
                    "    font-size: 170%;\n" +
                    "    text-align: left;\n" +
                    "    vertical-align: middle; \n" +
                    "    height: 32px; \n" +
                    "    margin-bottom: 10px;\n" +
                    "}\n" +
                    ".error-div {\n" +
                    "    display: inline-block;\n" +
                    "    width: 32px;\n" +
                    "    height: 32px;\n" +
                    "    background: url('') left center no-repeat;\n" +
                    "}\n" +
                    ".error-text-div {\n" +
                    "    display: inline-block;\n" +
                    "    vertical-align: top;\n" +
                    "    height: 32px;\n" +
                    "}\n" +
                    ".label {\n" +
                    "    font-weight:bold;\n" +
                    "    display: inline-block;\n" +
                    "}\n" +
                    ".value {\n" +
                    "    display: inline-block;\n" +
                    "    margin-left: 5px;\n" +
                    "}\n" +
                    "pre {\n" +
                    "    font-size: 110%;\n" +
                    "    margin-left: 1.5em;\n" +
                    "    white-space: pre-wrap;\n" +
                    "    white-space: -moz-pre-wrap;\n" +
                    "    white-space: -pre-wrap;\n" +
                    "    white-space: -o-pre-wrap;\n" +
                    "    word-wrap: break-word;\n" +
                    "}\n" +
                    "</style>";


    public static void handleRequest(HttpServerExchange exchange, final ServletRequestContext servletRequestContext, final Throwable exception) throws IOException {
        HttpServletRequestImpl req = servletRequestContext.getOriginalRequest();
        StringBuilder sb = new StringBuilder();
        //todo: make this good
        sb.append("<html><head><title>ERROR</title>");
        sb.append(ERROR_CSS);
        sb.append("</head><body><div class=\"header\"><div class=\"error-div\"></div><div class=\"error-text-div\">Error processing request</div></div>");
        writeLabel(sb, "Context Path", req.getContextPath());
        writeLabel(sb, "Servlet Path", req.getServletPath());
        writeLabel(sb, "Path Info", req.getPathInfo());
        writeLabel(sb, "Query String", req.getQueryString());
        writeLabel(sb, "Stack Trace", "");

        sb.append("<pre>");
        StringWriter stringWriter = new StringWriter();
        exception.printStackTrace(new PrintWriter(stringWriter));
        sb.append(escapeBodyText(stringWriter.toString()));
        sb.append("</pre></body></html>");
        servletRequestContext.getOriginalResponse().setContentType("text/html");
        servletRequestContext.getOriginalResponse().setCharacterEncoding("UTF-8");
        try {
            ServletOutputStream out = servletRequestContext.getOriginalResponse().getOutputStream();
            out.write(sb.toString().getBytes(StandardCharsets.UTF_8));
            out.close();
        } catch (IllegalStateException e) {
            PrintWriter writer = servletRequestContext.getOriginalResponse().getWriter();
            writer.write(sb.toString());
            writer.close();
        }
    }

    private static void writeLabel(StringBuilder sb, String label, String value) {
        sb.append("<div class=\"label\">");
        sb.append(escapeBodyText(label));
        sb.append(":</div><div class=\"value\">");
        sb.append(escapeBodyText(value));
        sb.append("</div><br/>");
    }

    public static String escapeBodyText(final String bodyText) {
        if(bodyText == null) {
            return "null";
        }
        return bodyText.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;");
    }
}
